#include <iostream>
#include <vector>
#include <cmath>
#include <algorithm>
#include <iomanip>
#include <random>

const int BUILDING_LENGTH = 100;
const int BUILDING_WIDTH = 80;
const int BUILDING_HEIGHT = 3;
const float FLOOR_HEIGHT = 3.5;

const int WALL_ATTENUATION[] = {12, 6, 7};
const float AP_COVERAGE_2_4GHZ = 15;
const float AP_COVERAGE_5GHZ = 10;

const int SIGNAL_THRESHOLD = -65;

const int CLASSROOM_LENGTH = 15;
const int CLASSROOM_WIDTH = 10;

const int CORRIDOR_WIDTH = 2;

enum WallType {
    LOAD_BEARING, PARTITION, GLASS
};
std::vector<std::vector<int>> buildingPlan;
void generateBuildingPlan() {
    buildingPlan.assign(BUILDING_LENGTH, std::vector<int>(BUILDING_WIDTH, 0));
    int corridorStart = (BUILDING_WIDTH - CORRIDOR_WIDTH) / 2;
    int corridorEnd = corridorStart + CORRIDOR_WIDTH;
    for (int i = 0; i < BUILDING_LENGTH; ++i) {
        for (int j = corridorStart; j < corridorEnd; ++j) {
            buildingPlan[i][j] = GLASS;
        }
    }
    for (int i = 0; i < BUILDING_LENGTH; i += CLASSROOM_LENGTH) {
        for (int j = 0; j < corridorStart; j += CLASSROOM_WIDTH) {
            for (int x = i; x < i + CLASSROOM_LENGTH && x < BUILDING_LENGTH; ++x) {
                for (int y = j; y < j + CLASSROOM_WIDTH && y < corridorStart; ++y) {
                    buildingPlan[x][y] = PARTITION;
                }
            }
        }
        for (int j = corridorEnd; j < BUILDING_WIDTH; j += CLASSROOM_WIDTH) {
            for (int x = i; x < i + CLASSROOM_LENGTH && x < BUILDING_LENGTH; ++x) {
                for (int y = j; y < j + CLASSROOM_WIDTH && y < BUILDING_WIDTH; ++y) {
                    buildingPlan[x][y] = PARTITION;
                }
            }
        }
    }
}
float calculateSignalStrength(int x, int y, int apX, int apY) {
    float distance = std::sqrt(std::pow(x - apX, 2) + std::pow(y - apY, 2));
    int wallType = buildingPlan[x][y];
    float attenuation = (wallType == LOAD_BEARING) ? WALL_ATTENUATION[0] :
                        (wallType == PARTITION) ? WALL_ATTENUATION[1] :
                        (wallType == GLASS) ? WALL_ATTENUATION[2] : 0;
    return -60 - 20 * std::log10(distance + 1) - attenuation;
}

void generateSignalHeatmap(int apX, int apY) {
    std::vector<std::vector<float>> signalMap(BUILDING_LENGTH, std::vector<float>(BUILDING_WIDTH, 0.0f));
    for (int i = 0; i < BUILDING_LENGTH; ++i) {
        for (int j = 0; j < BUILDING_WIDTH; ++j) {
            signalMap[i][j] = calculateSignalStrength(i, j, apX, apY);
        }
    }
    std::cout << "Signal Heatmap (dBm):" << std::endl;
    for (int i = 0; i < BUILDING_LENGTH; ++i) {
        for (int j = 0; j < BUILDING_WIDTH; ++j) {
            std::cout << std::fixed << std::setprecision(1) << signalMap[i][j] << " ";
        }
        std::cout << std::endl;
    }
}

std::pair<int, int> calculateBestAPLocation() {
    int bestX = BUILDING_LENGTH / 2;
    int bestY = BUILDING_WIDTH / 2;
    return {bestX, bestY};
}

int main() {
    generateBuildingPlan();
    auto [apX, apY] = calculateBestAPLocation();
    std::cout << "Best AP Location: (" << apX << ", " << apY << ")" << std::endl;
    generateSignalHeatmap(apX, apY);
    return 0;
}